home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / OldSrc / CH4 / SRC / ROTATEF.FRM (.txt) < prev    next >
Encoding:
Visual Basic Form  |  1997-01-03  |  14.9 KB  |  469 lines

  1. VERSION 4.00
  2. Begin VB.Form RotateForm 
  3.    Caption         =   "Rotate"
  4.    ClientHeight    =   4560
  5.    ClientLeft      =   1080
  6.    ClientTop       =   1290
  7.    ClientWidth     =   7680
  8.    Height          =   5250
  9.    Left            =   1020
  10.    LinkTopic       =   "Form1"
  11.    ScaleHeight     =   304
  12.    ScaleMode       =   3  'Pixel
  13.    ScaleWidth      =   512
  14.    Top             =   660
  15.    Width           =   7800
  16.    Begin VB.CommandButton CmdRotate 
  17.       Caption         =   "Rotate"
  18.       Default         =   -1  'True
  19.       Enabled         =   0   'False
  20.       Height          =   495
  21.       Left            =   1080
  22.       TabIndex        =   4
  23.       Top             =   3720
  24.       Width           =   855
  25.    End
  26.    Begin VB.TextBox AngleText 
  27.       Height          =   285
  28.       Left            =   1680
  29.       TabIndex        =   3
  30.       Text            =   "0"
  31.       Top             =   3120
  32.       Width           =   615
  33.    End
  34.    Begin VB.PictureBox ToPict 
  35.       AutoRedraw      =   -1  'True
  36.       BackColor       =   &H00C0C0C0&
  37.       Height          =   4560
  38.       Left            =   3120
  39.       Picture         =   "ROTATEF.frx":0000
  40.       ScaleHeight     =   300
  41.       ScaleMode       =   3  'Pixel
  42.       ScaleWidth      =   300
  43.       TabIndex        =   1
  44.       Top             =   0
  45.       Width           =   4560
  46.    End
  47.    Begin VB.PictureBox FromPict 
  48.       AutoRedraw      =   -1  'True
  49.       BackColor       =   &H00C0C0C0&
  50.       Height          =   3060
  51.       Left            =   0
  52.       Picture         =   "ROTATEF.frx":0446
  53.       ScaleHeight     =   200
  54.       ScaleMode       =   3  'Pixel
  55.       ScaleWidth      =   200
  56.       TabIndex        =   0
  57.       Top             =   0
  58.       Width           =   3060
  59.    End
  60.    Begin VB.Label Label1 
  61.       Caption         =   "Angle (degrees)"
  62.       Height          =   255
  63.       Left            =   480
  64.       TabIndex        =   2
  65.       Top             =   3120
  66.       Width           =   1215
  67.    End
  68.    Begin MSComDlg.CommonDialog FileDialog 
  69.       Left            =   2520
  70.       Top             =   3120
  71.       _Version        =   65536
  72.       _ExtentX        =   847
  73.       _ExtentY        =   847
  74.       _StockProps     =   0
  75.       CancelError     =   -1  'True
  76.    End
  77.    Begin VB.Menu mnuFile 
  78.       Caption         =   "&File"
  79.       Begin VB.Menu mnuFileLoad 
  80.          Caption         =   "&Load..."
  81.          Shortcut        =   ^L
  82.       End
  83.       Begin VB.Menu mnuFileSep 
  84.          Caption         =   "-"
  85.       End
  86.       Begin VB.Menu mnuFileExit 
  87.          Caption         =   "E&xit"
  88.       End
  89.    End
  90. Attribute VB_Name = "RotateForm"
  91. Attribute VB_Creatable = False
  92. Attribute VB_Exposed = False
  93. Option Explicit
  94. Dim SysPalSize As Integer
  95. Dim NumStaticColors As Integer
  96. Dim StaticColor1 As Integer
  97. Dim StaticColor2 As Integer
  98. Dim LogPal As Integer
  99. Dim palentry(0 To 255) As PALETTEENTRY
  100. Dim wid As Long
  101. Dim hgt As Long
  102. Dim bytes() As Byte
  103. ' ************************************************
  104. ' Draw the rotated image.
  105. ' ************************************************
  106. Sub DrawImage()
  107. Const PI = 3.14159
  108. Dim theta As Single
  109. Dim fcx As Integer
  110. Dim fcy As Integer
  111. Dim tcx As Integer
  112. Dim tcy As Integer
  113.     If Not IsNumeric(AngleText.Text) Then _
  114.         AngleText.Text = 0
  115.     theta = PI * CSng(AngleText.Text) / 180#
  116.     fcx = FromPict.ScaleWidth / 2
  117.     fcy = FromPict.ScaleHeight / 2
  118.     tcx = ToPict.ScaleWidth / 2
  119.     tcy = ToPict.ScaleHeight / 2
  120.     ToPict.Cls
  121.     RotatePicture FromPict, ToPict, theta, _
  122.         0, 0, _
  123.         FromPict.ScaleWidth - 1, _
  124.         FromPict.ScaleHeight - 1, _
  125.         fcx, fcy, tcx, tcy
  126. End Sub
  127. ' ************************************************
  128. ' Rotate the picture in from_pic and place it
  129. ' in to_pic. Rotate the area fx1 <= x <= fx2,
  130. ' fy1 <= y <= fy2 through angle theta radians
  131. ' around the point (cfx, cfy). Place the result so
  132. ' (cfx, cfy) maps to (ctx, cty).
  133. ' ************************************************
  134. Sub RotatePicture( _
  135.     ByVal from_pic As Control, ByVal to_pic As Control, _
  136.     ByVal theta As Single, _
  137.     ByVal fx1 As Integer, ByVal fy1 As Integer, _
  138.     ByVal fx2 As Integer, ByVal fy2 As Integer, _
  139.     ByVal cfx As Integer, ByVal cfy As Integer, _
  140.     ByVal ctx As Integer, ByVal cty As Integer)
  141. Dim bm As BITMAP
  142. Dim hbm As Integer
  143. Dim status As Long
  144. Dim from_bytes() As Byte
  145. Dim to_bytes() As Byte
  146. Dim from_wid As Long
  147. Dim from_hgt As Long
  148. Dim to_wid As Long
  149. Dim to_hgt As Long
  150. Dim sin_theta As Single
  151. Dim cos_theta As Single
  152. Dim tx1 As Integer
  153. Dim tx2 As Integer
  154. Dim ty1 As Integer
  155. Dim ty2 As Integer
  156. Dim tx As Integer
  157. Dim ty As Integer
  158. Dim fx As Single
  159. Dim fy As Single
  160. Dim ifx As Integer
  161. Dim ify As Integer
  162. Dim dx As Single
  163. Dim dy As Single
  164. Dim c1 As Integer
  165. Dim c2 As Integer
  166. Dim c3 As Integer
  167. Dim c4 As Integer
  168. Dim i1 As Integer
  169. Dim i2 As Integer
  170. Dim clr As Integer
  171.     ' Get from_pic's pixels.
  172.     hbm = from_pic.Image
  173.     status = GetObject(hbm, BITMAP_SIZE, bm)
  174.     from_wid = bm.bmWidthBytes
  175.     from_hgt = bm.bmHeight
  176.     ReDim from_bytes(0 To from_wid - 1, 0 To from_hgt - 1)
  177.     status = GetBitmapBits(hbm, from_wid * from_hgt, from_bytes(0, 0))
  178.     ' Get to_pic's pixels.
  179.     hbm = to_pic.Image
  180.     status = GetObject(hbm, BITMAP_SIZE, bm)
  181.     to_wid = bm.bmWidthBytes
  182.     to_hgt = bm.bmHeight
  183.     ReDim to_bytes(0 To to_wid - 1, 0 To to_hgt - 1)
  184.     status = GetBitmapBits(hbm, to_wid * to_hgt, to_bytes(0, 0))
  185.     ' Compute the sine and cosine of theta.
  186.     sin_theta = Sin(theta)
  187.     cos_theta = Cos(theta)
  188.         
  189.     ' Make some bounds for to_pic.
  190.     tx1 = (fx1 - cfx) * cos_theta + (fy1 - cfy) * sin_theta + ctx
  191.     ty1 = -(fx1 - cfx) * sin_theta + (fy1 - cfy) * cos_theta + cty
  192.     tx2 = tx1
  193.     ty2 = ty1
  194.     tx = (fx1 - cfx) * cos_theta + (fy2 - cfy) * sin_theta + ctx
  195.     ty = -(fx1 - cfx) * sin_theta + (fy2 - cfy) * cos_theta + cty
  196.     If tx1 > tx Then tx1 = tx
  197.     If ty1 > ty Then ty1 = ty
  198.     If tx2 < tx Then tx2 = tx
  199.     If ty2 < ty Then ty2 = ty
  200.     tx = (fx2 - cfx) * cos_theta + (fy1 - cfy) * sin_theta + ctx
  201.     ty = -(fx2 - cfx) * sin_theta + (fy1 - cfy) * cos_theta + cty
  202.     If tx1 > tx Then tx1 = tx
  203.     If ty1 > ty Then ty1 = ty
  204.     If tx2 < tx Then tx2 = tx
  205.     If ty2 < ty Then ty2 = ty
  206.     tx = (fx2 - cfx) * cos_theta + (fy2 - cfy) * sin_theta + ctx
  207.     ty = -(fx2 - cfx) * sin_theta + (fy2 - cfy) * cos_theta + cty
  208.     If tx1 > tx Then tx1 = tx
  209.     If ty1 > ty Then ty1 = ty
  210.     If tx2 < tx Then tx2 = tx
  211.     If ty2 < ty Then ty2 = ty
  212.     If tx1 < 1 Then tx1 = 1
  213.     If tx2 < 1 Then tx2 = 1
  214.     If tx1 > to_wid - 1 Then tx1 = to_wid - 1
  215.     If tx2 > to_wid - 1 Then tx2 = to_wid - 1
  216.     If ty1 < 1 Then ty1 = 1
  217.     If ty2 < 1 Then ty2 = 1
  218.     If ty1 > to_hgt - 1 Then ty1 = to_hgt - 1
  219.     If ty2 > to_hgt - 1 Then ty2 = to_hgt - 1
  220.     ' Perform the rotation.
  221.     For ty = ty1 To ty2
  222.         For tx = tx1 To tx2
  223.             ' Find the location (fx, fy) that maps
  224.             ' to the pixel (tx, ty).
  225.             fx = (tx - ctx) * cos_theta - (ty - cty) * sin_theta + cfx
  226.             fy = (tx - ctx) * sin_theta + (ty - cty) * cos_theta + cfy
  227.             ' Skip it if any of the four nearest
  228.             ' source pixels lie outside the allowed
  229.             ' source area.
  230.             ify = Int(fy)
  231.             ifx = Int(fx)
  232.             If ifx >= fx1 And ifx < fx2 And _
  233.                ify >= fy1 And ify < fy2 Then
  234.                 ' Interpolate using the four nearest
  235.                 ' pixels in from_pic.
  236.                 dy = fy - ify
  237.                 dx = fx - ifx
  238.                 c1 = palentry(from_bytes(ifx, ify)).peRed
  239.                 c2 = palentry(from_bytes(ifx + 1, ify)).peRed
  240.                 c3 = palentry(from_bytes(ifx, ify + 1)).peRed
  241.                 c4 = palentry(from_bytes(ifx + 1, ify + 1)).peRed
  242.                 ' Interpolate in the Y direction.
  243.                 i1 = c1 * (1 - dy) + c3 * dy
  244.                 i2 = c2 * (1 - dy) + c4 * dy
  245.                 ' Interpolate the results in the X direction.
  246.                 clr = i1 * (1 - dx) + i2 * dx
  247.                 to_bytes(tx, ty) = NearestNonstaticGray(clr)
  248.             End If
  249.         Next tx
  250.     Next ty
  251.     ' Update from_pic.
  252.     status = SetBitmapBits(hbm, to_wid * to_hgt, to_bytes(0, 0))
  253.     to_pic.Refresh
  254. End Sub
  255. ' ***********************************************
  256. ' Load the control's palette so the non-static
  257. ' colors are grays. Map the logical palette to
  258. ' match the system palette. Convert the image to
  259. ' use the non-static grays.
  260. ' Set the following module global variables.
  261. '   LogPal      Image logical palette handle.
  262. '   palentry()  Image logical palette entries.
  263. '   wid         Width of image.
  264. '   hgt         Height of image.
  265. '   bytes(1 To wid, 1 To hgt)
  266. '               Image pixel values.
  267. ' ***********************************************
  268. Sub MatchGrayPalette(pic As Control)
  269. Dim sys(0 To 255) As PALETTEENTRY
  270. Dim i As Integer
  271. Dim bm As BITMAP
  272. Dim hbm As Integer
  273. Dim status As Long
  274. Dim X As Integer
  275. Dim Y As Integer
  276. Dim gray As Single
  277. Dim dgray As Single
  278. Dim c As Integer
  279. Dim clr As Integer
  280.     ' Make sure pic has the foreground palette.
  281.     pic.ZOrder
  282.     i = RealizePalette(pic.hdc)
  283.     DoEvents
  284.     ' Get the system palette entries.
  285.     i = GetSystemPaletteEntries(pic.hdc, 0, SysPalSize, sys(0))
  286.         
  287.     ' Get the image pixels.
  288.     hbm = pic.Image
  289.     status = GetObject(hbm, BITMAP_SIZE, bm)
  290.     wid = bm.bmWidthBytes
  291.     hgt = bm.bmHeight
  292.     ReDim bytes(1 To wid, 1 To hgt)
  293.     status = GetBitmapBits(hbm, wid * hgt, bytes(1, 1))
  294.     ' Make the logical palette as big as possible.
  295.     LogPal = pic.Picture.hPal
  296.     If ResizePalette(LogPal, SysPalSize) = 0 Then
  297.         Beep
  298.         MsgBox "Error resizing logical palette.", _
  299.             vbExclamation
  300.         Exit Sub
  301.     End If
  302.     ' Blank the non-static colors.
  303.     For i = 0 To StaticColor1
  304.         palentry(i) = sys(i)
  305.     Next i
  306.     For i = StaticColor1 + 1 To StaticColor2 - 1
  307.         With palentry(i)
  308.             .peRed = 0
  309.             .peGreen = 0
  310.             .peBlue = 0
  311.             .peFlags = PC_NOCOLLAPSE
  312.         End With
  313.     Next i
  314.     For i = StaticColor2 To 255
  315.         palentry(i) = sys(i)
  316.     Next i
  317.     i = SetPaletteEntries(LogPal, 0, SysPalSize, palentry(0))
  318.     ' Insert the non-static grays.
  319.     gray = 0
  320.     dgray = 255 / (StaticColor2 - StaticColor1 - 2)
  321.     For i = StaticColor1 + 1 To StaticColor2 - 1
  322.         c = gray
  323.         gray = gray + dgray
  324.         With palentry(i)
  325.             .peRed = c
  326.             .peGreen = c
  327.             .peBlue = c
  328.         End With
  329.     Next i
  330.     i = SetPaletteEntries(LogPal, StaticColor1 + 1, StaticColor2 - StaticColor1 - 1, palentry(StaticColor1 + 1))
  331.     ' Recreate the image using the new colors.
  332.     For Y = 1 To hgt
  333.         For X = 1 To wid
  334.             clr = bytes(X, Y)
  335.             With sys(clr)
  336.                 c = (CInt(.peRed) + .peGreen + .peBlue) / 3
  337.             End With
  338.             bytes(X, Y) = NearestNonstaticGray(c)
  339.         Next X
  340.     Next Y
  341.     status = SetBitmapBits(hbm, wid * hgt, bytes(1, 1))
  342.     ' Realize the gray palette.
  343.     i = RealizePalette(pic.hdc)
  344.     pic.Refresh
  345. End Sub
  346. ' ************************************************
  347. ' Return the index of the nonstatic gray closest
  348. ' to the given value (assuming the non-static
  349. ' colors are a gray scale created by
  350. ' MatchGrayPalette).
  351. ' ************************************************
  352. Function NearestNonstaticGray(c As Integer) As Integer
  353. Dim dgray As Single
  354.     If c < 0 Then
  355.         c = 0
  356.     ElseIf c > 255 Then
  357.         c = 255
  358.     End If
  359.     dgray = 255 / (StaticColor2 - StaticColor1 - 2)
  360.     NearestNonstaticGray = c / dgray + StaticColor1 + 1
  361. End Function
  362. ' ************************************************
  363. ' Draw the rotated image.
  364. ' ************************************************
  365. Private Sub CmdRotate_Click()
  366.     WaitStart
  367.     DrawImage
  368.     WaitEnd
  369. End Sub
  370. Private Sub Form_Load()
  371. Dim i As Integer
  372.     ' Make sure the screen supports palettes.
  373.     If Not GetDeviceCaps(hdc, RASTERCAPS) And RC_PALETTE Then
  374.         Beep
  375.         MsgBox "This monitor does not support palettes.", _
  376.             vbCritical
  377.         End
  378.     End If
  379.     ' Get system palette size and # static colors.
  380.     SysPalSize = GetDeviceCaps(hdc, SIZEPALETTE)
  381.     NumStaticColors = GetDeviceCaps(hdc, NUMRESERVED)
  382.     StaticColor1 = NumStaticColors \ 2 - 1
  383.     StaticColor2 = SysPalSize - NumStaticColors \ 2
  384.     ' Make the pictures all use gray palettes.
  385.     Me.Show
  386.     DoEvents
  387.     WaitStart
  388.     MatchGrayPalette ToPict
  389.     DoEvents
  390.     ' Let each image repair its palette if needed.
  391.     FromPict.ZOrder
  392.     DoEvents
  393.     ToPict.ZOrder
  394.     DoEvents
  395.     WaitEnd
  396. End Sub
  397. ' ***********************************************
  398. ' Reset the cursors for the form and all the
  399. ' picture boxes.
  400. ' ***********************************************
  401. Sub WaitEnd()
  402.     MousePointer = vbDefault
  403.     FromPict.MousePointer = vbDefault
  404.     ToPict.MousePointer = vbDefault
  405. End Sub
  406. ' ***********************************************
  407. ' Give the form and all the picture boxes an
  408. ' hourglass cursor.
  409. ' ***********************************************
  410. Sub WaitStart()
  411.     MousePointer = vbHourglass
  412.     FromPict.MousePointer = vbHourglass
  413.     ToPict.MousePointer = vbHourglass
  414.     DoEvents
  415. End Sub
  416. Private Sub Form_Unload(Cancel As Integer)
  417.     End
  418. End Sub
  419. Private Sub mnuFileExit_Click()
  420.     Unload Me
  421. End Sub
  422. ' ***********************************************
  423. ' Load a new image file.
  424. ' ***********************************************
  425. Private Sub mnuFileLoad_Click()
  426. Dim fname As String
  427.     ' Allow the user to pick a file.
  428.     On Error Resume Next
  429.     FileDialog.filename = "*.BMP;*.ICO;*.RLE;*.WMF;*.DIB"
  430.     FileDialog.Flags = cdlOFNFileMustExist + cdlOFNHideReadOnly
  431.     FileDialog.ShowOpen
  432.     If Err.Number = cdlCancel Then
  433.         Exit Sub
  434.     ElseIf Err.Number <> 0 Then
  435.         Beep
  436.         MsgBox "Error selecting file.", , vbExclamation
  437.         Exit Sub
  438.     End If
  439.     On Error GoTo 0
  440.     fname = Trim$(FileDialog.filename)
  441.     FileDialog.InitDir = Left$(fname, Len(fname) _
  442.         - Len(FileDialog.FileTitle) - 1)
  443.     ' Load the picture.
  444.     WaitStart
  445.     LoadFromPict fname
  446.     DrawImage
  447.     WaitEnd
  448. End Sub
  449. ' ***********************************************
  450. ' Load the indicated file and prepare to work
  451. ' with its palette.
  452. ' ***********************************************
  453. Sub LoadFromPict(fname As String)
  454. Dim status As Long
  455.     On Error GoTo LoadFileError
  456.     FromPict.Picture = LoadPicture(fname)
  457.     On Error GoTo 0
  458.         
  459.     MatchGrayPalette FromPict
  460.     Caption = "Rotate [" & fname & "]"
  461.     CmdRotate.Enabled = True
  462.     Exit Sub
  463. LoadFileError:
  464.     Beep
  465.     MsgBox "Error loading file " & fname & "." & _
  466.         vbCrLf & Error$
  467.     Exit Sub
  468. End Sub
  469.